//
//      Copyright Timothy Evans 2014    timothy.evans@gsecraif.org
//
//      This file is part of gsecraif.
//
//      gsecraif is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 3 of the License, or
//      (at your option) any later version.
//
//      See gsecraif.cpp
//
// =====================================================================
//
//! Implement stripe.
//
// =====================================================================
// 
// Compile with g++

#include "stripe.h"

using namespace std;


int Stripe::position_of_parity()  {
    return parity_position;
};

void Stripe::increase_parity_pos() {
    ++parity_position;
    if (parity_position == bytes.size() ) {
        parity_position = 0; // wrap around
        }
};

void Stripe::decrease_parity_pos()  {
    --parity_position;
    if (parity_position < 0) {
        parity_position = bytes.size() -1; // wrap around
        }
};


void Stripe::rotate_stripe(int stripestart)  {
    // rotate the bytes:
    std::rotate(bytes.begin(), bytes.begin() +stripestart, bytes.end() );
    // move the position of the parity bytes
    for (int position=0; position != stripestart; ++position) {
        decrease_parity_pos();
        }
};


// de-rotate the stripe
void Stripe::de_rotate_stripe(int stripestart)  {
    // de-rotate the bytes:
    std::rotate(bytes.begin(), bytes.begin() + (bytes.size() - stripestart),
                bytes.end() );
    // move the position of the parity bytes
    for (int position=0; position != (bytes.size() -stripestart); ++position) {
        decrease_parity_pos();
        }
};

// repair stipe with "bad" byte at pos_bad_byte
void Stripe::repair_stripe(int pos_bad_byte)  {
    char repaired_byte;
    int preserve_parity_position = parity_position;
    vector<unsigned char> temp_slice;
    // temp set the parity position to where the "bad" byte is
    // so that a vector of all the other bytes can be extracted
    // with slice_from_stripe

    parity_position = pos_bad_byte;
    // initialize:
    for (int byte=0; byte != (bytes.size() -1); ++byte)  {
        temp_slice.push_back(0);
        }
    temp_slice = slice_from_stripe();
    repaired_byte = parity(temp_slice);
    bytes[pos_bad_byte] = repaired_byte; // fixed.
    // clean up:
    parity_position = preserve_parity_position;

};

// convert slice to stripe
// stripe is one more byte longer than slice - the parity byte.
void Stripe::slice_to_stripe(vector<unsigned char> slice)  {
    vector<unsigned char>::iterator byte;
    int bytes_pos = 0;
    if ( (bytes.size() - slice.size()) == 1 ) {
        for (byte = slice.begin(); byte != slice.end(); ++byte) {
            bytes[bytes_pos] = *byte;
            ++bytes_pos;
            }
        bytes.back() = parity(slice);  // calculate the parity
                                       // and assign to last byte
        }

};


// return slice from stripe
vector<unsigned char> Stripe::slice_from_stripe() {
    vector<unsigned char> slice;
    int start_of_slice = parity_position + 1;  // position of start of slice
                                               // (1 beyond parity position)
    int end_of_slice = 0; // parity_position - 1
// When the parity position is the end of the stripe (default),
// start wraps around to 0.
    if (start_of_slice > (bytes.size() -1) ) {
        start_of_slice = 0;
        }
    if (parity_position > 0) {
        end_of_slice = parity_position - 1;
        }
    else {
        end_of_slice = bytes.size() -1;
        }
    // extract slice:    
    if (parity_position == 0) {
        for (int byte = start_of_slice; byte != bytes.size(); ++byte)  {
            slice.push_back(bytes[byte]);
            }
        }
    else if  (parity_position == (bytes.size() -1) ) {
	for (int byte = 0; byte <= end_of_slice; ++byte)  {
            slice.push_back(bytes[byte]);
            }
        }
    else {                        
        // copy bytes from start of slice (1 past parity)
        // to end of stripe to the slice
        for (int byte = start_of_slice; byte != bytes.size(); ++byte)  {
            slice.push_back(bytes[byte]);
            }
        // copy bytes from start of stripe to end of slice (1 before parity)
        // to the slice
        for (int byte = 0; byte <= end_of_slice; ++byte)  {
            slice.push_back(bytes[byte]);
            }
        }
    return slice;
}; 


// return byte at location - position
unsigned char Stripe::get_byte(int position)  {
    assert(position >= 0);
    if ((position >= 0) && (position <= bytes.size() -1)) {    
        return bytes[position];
	    }
    else {
        abort();
        }
};


// assign byte at location - position
void Stripe::put_byte(int position, unsigned char byte)  {
    if ((position >= 0) && (position <= bytes.size() -1)) {	
        bytes[position] = byte;
	    }
};

// ======================================================================
